#pragma once
#ifndef __THREADPOOL_H__
#define __THREADPOOL_H__

#include <vector>
#include <deque>
#include <functional>
#include <future>
#include <queue>
#include <mutex>
#include <memory>
#include <condition_variable>
#include <thread>



class ThreadPool{
public:
    ThreadPool() = default;
    ~ThreadPool() = default; // 析构里面要Join
    void start(size_t thread_nums = 4){
        threads.resize(thread_nums);
        for (int i = 0; i < thread_nums; i++)
            threads[i] = std::thread(&ThreadPool::thread_function, this);
    }

    template<typename Function, typename ... Args>
    auto submit(Function&& function, Args&& ... args)->std::future<decltype(function(args...))>{
        using ReturnType = decltype(function(args...));
        auto task = std::make_shared<std::packaged_task<ReturnType()>> 
            (std::bind(std::forward<Function>(function), std::forward<Args>(args)...));

        std::future<ReturnType> result = task->get_future();

        std::unique_lock<std::mutex> lock(task_queue_mutex);
        task_queue.emplace([task](){(*task)();});
        task_queue_not_empty.notify_one();
        return result;
    }
private:
    void thread_function(){
        while (true)
        {
            Task task;
            {
            std::unique_lock<std::mutex> lock(task_queue_mutex);
            task_queue_not_empty.wait(lock, [this](){return !this->task_queue.empty();});
            task = task_queue.front();
            task_queue.pop();
            }

            task();
        }
    }
private:
    using Task = std::function<void()>;
    std::queue<Task> task_queue;
    std::mutex task_queue_mutex;
    std::condition_variable task_queue_not_empty;
    std::vector<std::thread> threads;
};

#endif // __THREADPOOL_H__